///////////////////////////////////////////////////////////////////////////////
//	FILENAME:	eTextContainer.m
//	SUMMARY:	Implementation of a general container for eText regions
//	SUPERCLASS:	Object
//	INTERFACE:	None
//	PROTOCOLS:	None
//	AUTHOR:		Rohit Khare
//	COPYRIGHT:	(c) 1994 California Institure of Technology, eText Project
///////////////////////////////////////////////////////////////////////////////
//  IMPLEMENTATION COMMENTS
//		fragile. How to ensure that we have the only "live" handles to the
//	various embedded objects
///////////////////////////////////////////////////////////////////////////////
//	HISTORY
//	05/08/94:	Created. First actual implementation.
//	Late 93/4	Prototyped and tested in TextTest.app
///////////////////////////////////////////////////////////////////////////////

#import "eTextContainer.h"

@implementation eTextContainer
// 	id			theText
// 	char		*theChars;
// 	NXRunArray  *theRuns;
// 	int			nRuns, nChars;

- init
{
	[super init];
	theText = nil;
	theChars = NULL;
	theRuns = NULL;
	return self;
}

- collapse:newText
{
	NXSelPt start, end;
	int total = 0;
	NXRun *currentRun, *nextRun;
	int nextRunCnt;
	

	// cut: the contents into a copy in our members
	theText = newText;
	[theText getSel:&start :&end];
	nChars = end.cp - start.cp;
	theChars = malloc((nChars+1)  * sizeof(wchar));
	[theText getSubstring:theChars start:start.cp length:nChars];
	if (!theChars[nChars-1]) { // this is for smartcopy/smartpaste
		nChars--;
		end.cp--;
	}
	if (!theRuns) theRuns = (NXRunArray *)NXChunkZoneMalloc(sizeof(NXRun), sizeof(NXRun), [self zone]);
	theRuns->chunk.used = 0;
	total = 0;
	currentRun = [theText theRuns]->runs;
	nRuns = nextRunCnt = 0;
	while (total < end.cp) {
		if ((total + currentRun->chars) > start.cp) {
			// do we need to alloc more space?
			if (theRuns->chunk.used == theRuns->chunk.allocated) {
				theRuns=(NXRunArray *)NXChunkZoneRealloc((NXChunk *)theRuns,[self zone]);
			}
			theRuns->chunk.used += sizeof(NXRun);
			nextRun = (theRuns->runs) + nextRunCnt++; nRuns++;
			*nextRun = *currentRun;
			// how many characters are in our copy?
			// the current run extends from total to total+chars
			// we want chars from start.cp to end.cp.
			// the end points are MAX(start.cp, total) and
			// MIN(total+chars, end.cp) -- and the length is the diff.
			nextRun->chars= MIN(total + currentRun->chars, end.cp) -
							MAX(total, start.cp);
			// zero-out the info-fields so they don't get freed
			currentRun->info = nil;
		}
		total += currentRun->chars;
		currentRun++;
	}
	// In an undo-enabled system, we want to have a non-traceable delete:
	[[theText undoManager] disableUndoRegistration];
	[theText delete:self];
	[[theText undoManager] reenableUndoRegistration];
	return self;
}

- expand:newText
{
	[[theText undoManager] disableUndoRegistration];
	[theText replaceSel:theChars length:nChars runs:theRuns];
	[[theText undoManager] reenableUndoRegistration];
	free(theChars); theChars = NULL;
	theRuns->chunk.used = 0;
	theText = nil;
	return self;
}

- free
{
	if (theChars) free(theChars);
	if (theRuns && theRuns->chunk.used != 0) {
		free(theRuns);
	}
	return self = [super free];
}
@end